#include <glib.h>
#include <string.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 

#include <curl/curl.h> 
#include <curl/easy.h> 


#include "config.h"
#include "sys_log.h"

typedef void (*http_rec)(char* buf, long buf_len, char* content_type, void* usr_data);

typedef struct
{
	//file
	FILE	*fp;
	char	*file_path_name;
	long 	file_size;
	//buf
	char	*buf;
	long	buf_len;
	//url
	char 	*url;
	//callback
	//void (*app_rec)(char* buf, long buf_len, int file_flag, char* content_type);
	http_rec app_rec;
	void*	 app_rec_usr_data;
}http_client_handler_s;


static long write_data_to_file(void *data, int size, int nmemb, http_client_handler_s *httpclient)
{


    long sizes = size * nmemb;
    if(sizes==0) {
        SYS_LOG("write_data_to_file receive data error");
        printf("write_data_to_file receive data error\n");
        return -1;
    }
	httpclient->file_size = httpclient->file_size+sizes;
	int written = fwrite(data, size, nmemb, httpclient->fp); 

	return written; 
}


static CURL *curl_init(http_client_handler_s *httpclient)
{
    CURLcode code;
    char error[100];
	CURL *curl= NULL;

    curl = curl_easy_init();
    if (curl == NULL) {
        SYS_LOG( "Failed to create CURL connection");
        return curl;
    }
    code = curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, error);
    if (code != CURLE_OK)
    {
        SYS_LOG( "Failed to set error buffer [%d]", code );
	    curl_easy_cleanup(curl);
        return NULL;
    }
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    code = curl_easy_setopt(curl, CURLOPT_URL, httpclient->url);
    if (code != CURLE_OK)
    {
        SYS_LOG("Failed to set URL [%s]", error);
	    curl_easy_cleanup(curl);
        return NULL;
    }
    code = curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1);
    if (code != CURLE_OK)
    {
        SYS_LOG( "Failed to set redirect option [%s]", error );
	    curl_easy_cleanup(curl);
        return NULL;
    }
    code = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data_to_file);
    if (code != CURLE_OK)
    {
        SYS_LOG( "Failed to set writer [%s]", error);
	    curl_easy_cleanup(curl);
        return NULL;
    }
	
    code = curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpclient);
    if (code != CURLE_OK)
    {
        SYS_LOG( "Failed to set write data [%s]", error );
	    curl_easy_cleanup(curl);
        return NULL;
    }
    code = curl_easy_setopt(curl, CURLOPT_TIMEOUT,60);
    if (code != CURLE_OK)
    {
        SYS_LOG( "Failed to set write data [%s]", error );
	    curl_easy_cleanup(curl);
        return NULL;
    }
    return curl;
}

static void destory_httpclient_s(http_client_handler_s *httpclient)
{
//	SYS_LOG( "destory_httpclient_s in\n");

	if (NULL == httpclient) return;

	if (NULL != httpclient->fp) 			fclose(httpclient->fp);
	if (NULL != httpclient->file_path_name) free(httpclient->file_path_name);
	if (NULL != httpclient->url) 			free(httpclient->url);
	if (NULL != httpclient->buf) 			free(httpclient->buf);

	free(httpclient);
	httpclient = NULL;
//	SYS_LOG( "destory_httpclient_s out\n");
}

static char* genRandomString(int length)  
{  
    int flag, i;  
    char* string;  
    srand((unsigned) time(NULL ));  
    if ((string = (char*) malloc(length)) == NULL )  
    {  
        SYS_LOG("Malloc failed!flag:14");  
        return NULL ;  
    }  
  
    for (i = 0; i < length - 1; i++)  
    {  
        flag = rand() % 3;  
        switch (flag)  
        {  
            case 0:  
                string[i] = 'A' + rand() % 26;  
                break;  
            case 1:  
                string[i] = 'a' + rand() % 26;  
                break;  
            case 2:  
                string[i] = '0' + rand() % 10;  
                break;  
            default:  
                string[i] = 'x';  
                break;  
        }  
    }  
    string[length - 1] = '\0';  
    return string;  
}  



gboolean get_data_by_url(char* URL, char* file_path_name, void* rec_cb, void* usr_data)
{
    CURL *curl = NULL;
    CURLcode code;

	http_client_handler_s *httpclient = (http_client_handler_s *)malloc(sizeof(http_client_handler_s));
	memset(httpclient,0,sizeof(http_client_handler_s));

	SYS_LOG( "get_data_by_url in[%s][%s]",URL,file_path_name);


	httpclient->file_path_name = g_strdup(file_path_name);
	httpclient->url = g_strdup(URL);
	httpclient->app_rec = rec_cb;
	httpclient->app_rec_usr_data = usr_data;
		
    if ( (curl= curl_init(httpclient)) == NULL )
    {
        SYS_LOG( "Failed to global init default" );
        printf("Failed to global init default\n");
		goto error_handle;
    }
	if(0 == access(httpclient->file_path_name,F_OK)){//exist
		char tmpfile[1024] = {0};
		char *flag = NULL;
		char *randam_str = NULL;

		flag = g_strrstr(httpclient->file_path_name,".");
		strncpy(tmpfile,httpclient->file_path_name,flag - httpclient->file_path_name);
		randam_str = genRandomString(8);
		strcat(tmpfile,randam_str);
		strcat(tmpfile,flag);
		free(httpclient->file_path_name);
		free(randam_str);
		httpclient->file_path_name = g_strdup(tmpfile);
        sprintf(file_path_name,"%s",tmpfile);
        printf("http file exist and remove it [%s]\n",file_path_name);

	}
	if((httpclient->fp = fopen(httpclient->file_path_name,"w"))==NULL) { 
         printf("Failed to fopen[%s]\n", httpclient->file_path_name);
		goto error_handle;
	} 

    code = curl_easy_perform(curl);

    if (code != CURLE_OK) {
        SYS_LOG( "Failed to get [%s]", URL);
        printf("Failed to get[%s]\n", URL);
		goto error_handle;
    }

    long retcode = 0;
	char* content_type = NULL;
    code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE , &retcode); 
	fclose(httpclient->fp);
	httpclient->fp = NULL;
    if ( (code == CURLE_OK) && retcode == 200 ) {
        double length = 0;
        code = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD , &length);
		curl_easy_getinfo(curl,CURLINFO_CONTENT_TYPE,&content_type);

		if(httpclient->file_size ==  (long)length) {
			httpclient->app_rec(httpclient->file_path_name,httpclient->file_size,content_type,httpclient->app_rec_usr_data);
		} else {
			httpclient->app_rec(httpclient->file_path_name,httpclient->file_size,content_type,httpclient->app_rec_usr_data);
			//remove(httpclient->file_path_name);
		}
		curl_easy_cleanup(curl);
		destory_httpclient_s(httpclient);
        return TRUE;
    }

error_handle:
    curl_easy_cleanup(curl);
	httpclient->app_rec(httpclient->file_path_name,httpclient->file_size,NULL,httpclient->app_rec_usr_data);
	destory_httpclient_s(httpclient);
	SYS_LOG( "get_data_by_url out error");
   	printf( "get_data_by_url out error\n");
    return FALSE;
}



static long http_heart_beat_data(void *data, int size, int nmemb, http_client_handler_s* httpclient)
{
    long sizes = size * nmemb;

	memcpy(httpclient->buf+httpclient->buf_len, data, sizes);
	httpclient->buf_len= httpclient->buf_len+sizes;

	return sizes;
}

gboolean http_heart_beat_post(char* url, char* buf, void* heart_beat_callback, void* callback_usr_data)
{
    CURLcode code;
    char error[100];
	CURL *curl= NULL;

	http_client_handler_s *httpclient = (http_client_handler_s *)malloc(sizeof(http_client_handler_s));
	memset(httpclient,0,sizeof(http_client_handler_s));

	httpclient->url = g_strdup(url);
	httpclient->app_rec = (http_rec)heart_beat_callback;
	httpclient->app_rec_usr_data = callback_usr_data;

	httpclient->buf = (char*)malloc(10*1024);
	memset(httpclient->buf, 0, sizeof(httpclient->buf));

   	curl = curl_easy_init();
    if (curl == NULL) {
        SYS_LOG( "Failed to create CURL connection");
		goto error_handle;
    }
    curl_easy_setopt(curl, CURLOPT_URL, url);
	//curl_easy_setopt(curl, CURLOPT_USERAGENT, "User-Agent: Mozilla/4.0 my test");
    curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buf);   
    curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, http_heart_beat_data);   
    curl_easy_setopt(curl, CURLOPT_WRITEDATA, httpclient);   
    curl_easy_setopt(curl, CURLOPT_POST, 1);   
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    curl_easy_setopt(curl, CURLOPT_TIMEOUT,10);
//    curl_easy_setopt(curl, CURLOPT_HEADER, 1); 

	struct curl_slist *headers=NULL;
	headers = curl_slist_append(headers, "Content-Type: text/xml; charset=utf-8");
	headers = curl_slist_append(headers, "Connection: close");
    curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

	code = curl_easy_perform(curl);
	if (code != CURLE_OK){
		SYS_LOG( "Failed to get [%s]", url);
		goto error_handle;

	}
	
	long retcode = 0;
	char* content_type = NULL;
	code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE , &retcode); 
	curl_easy_getinfo(curl,CURLINFO_CONTENT_TYPE,&content_type);
	if ( (code == CURLE_OK) && retcode == 200 ) {

		double recv_length = 0;
		code = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD , &recv_length);

		if(httpclient->buf_len ==  (long)recv_length) {
 			httpclient->app_rec(httpclient->buf,httpclient->buf_len,content_type,httpclient->app_rec_usr_data);
		} else {
			httpclient->app_rec(httpclient->buf,httpclient->buf_len,content_type,httpclient->app_rec_usr_data);
		}
		curl_easy_cleanup(curl);
		destory_httpclient_s(httpclient);

		return TRUE;
	}


error_handle:

	curl_easy_cleanup(curl);
	httpclient->app_rec(httpclient->buf,httpclient->buf_len,NULL,httpclient->app_rec_usr_data);
	destory_httpclient_s(httpclient);
	SYS_LOG( "http_heart_beat_post error");
    return FALSE;
}

gboolean http_upload_post(char* url, char* file_name, void* heart_beat_callback, void* callback_usr_data)
{
    CURLcode code;
    char error[100];
	CURL *curl= NULL;

	http_client_handler_s *httpclient = (http_client_handler_s *)malloc(sizeof(http_client_handler_s));
	memset(httpclient,0,sizeof(http_client_handler_s));

	httpclient->url = g_strdup(url);
	httpclient->app_rec = (http_rec)heart_beat_callback;
	httpclient->app_rec_usr_data = callback_usr_data;

   	curl = curl_easy_init();
    if (curl == NULL) {
        SYS_LOG( "Failed to create CURL connection");
		goto error_handle;
    }
	curl_easy_setopt(curl, CURLOPT_URL,url);
	struct curl_httppost *post = NULL; 
	struct curl_httppost *last = NULL;
	curl_formadd(&post,&last, CURLFORM_COPYNAME, "name",CURLFORM_COPYCONTENTS, "Webprint",CURLFORM_END);
	curl_formadd(&post,&last, CURLFORM_COPYNAME, "address",CURLFORM_COPYCONTENTS, "Webprint", CURLFORM_END);  

	curl_formadd(&post,&last, CURLFORM_COPYNAME, "file",CURLFORM_FILECONTENT, file_name, CURLFORM_END);	
	curl_easy_setopt(curl, CURLOPT_HTTPPOST,post);	

	code = curl_easy_perform(curl);
	if (code != CURLE_OK){
		SYS_LOG( "Failed to post [%s]", file_name);
		goto error_handle;

	}
	curl_formfree(post);
	
	long retcode = 0;
	char* content_type = NULL;
	code = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE , &retcode); 
	curl_easy_getinfo(curl,CURLINFO_CONTENT_TYPE,&content_type);
	if ( (code == CURLE_OK) && retcode == 200 ) {

		double recv_length = 0;
		code = curl_easy_getinfo(curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD , &recv_length);

		if(httpclient->buf_len ==  (long)recv_length) {
 			httpclient->app_rec(httpclient->buf,httpclient->buf_len,content_type,httpclient->app_rec_usr_data);
		} else {
			httpclient->app_rec(httpclient->buf,httpclient->buf_len,content_type,httpclient->app_rec_usr_data);
		}
		curl_easy_cleanup(curl);
		destory_httpclient_s(httpclient);
		return TRUE;
	}

error_handle:
	curl_formfree(post);
	curl_easy_cleanup(curl);
	httpclient->app_rec(httpclient->buf,httpclient->buf_len,NULL,httpclient->app_rec_usr_data);
	destory_httpclient_s(httpclient);
	SYS_LOG( "http_upload_post error");
    return FALSE;
}

/*
void main()
{
    char *url ="http://www.baidu.com/img/baidu.gif";
    string content;
    if ( get_data_by_url(url,content))
    {
        SYS_LOG("%s\n",content);

    }
    getchar();
}*/
